package top.letscode.study.apollo.refresh;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import top.letscode.study.apollo.constant.Keys;
import top.letscode.study.apollo.constant.Namespaces;
import top.letscode.study.apollo.util.FileUtil;

import javax.annotation.PostConstruct;
import java.net.URL;

/**
 * @Author: zhengzhq
 * @Date: 2019-09-02 11:27
 * @Description: logback配置重新加载
 */
@Configuration
public class LogbackConfigurationRefresher {

    private static Logger logger = LoggerFactory.getLogger(LogbackConfigurationRefresher.class);
    private static final String LOGBACK_COMMON_FILE_NAME = "logback-common.xml";

    @ApolloConfig(Namespaces.LOGBACK_COMMON)
    private Config config;

    @PostConstruct
    public void postConstruct() {
        writeAndReloadLogbackConfig(config.getProperty(Keys.LOGBACK_COMMON, ""));
    }

    /**
     * 监听logback自定义配置的变化，有变化及时写入本地并加载
     *
     * @param changeEvent
     */
    @ApolloConfigChangeListener(value = {Namespaces.LOGBACK_COMMON}, interestedKeys = {Keys.LOGBACK_COMMON})

    public void refresh(ConfigChangeEvent changeEvent) {
        boolean isLogbackConfigChanged = changeEvent.isChanged(Keys.LOGBACK_COMMON);

        logger.debug("logback configuration changed: ", isLogbackConfigChanged);
        // 再次确认下该配置项是否有发生变化，原则上interestedKeys已经确保有变化了
        if (!isLogbackConfigChanged) {
            return;
        }

        String newConfiguration = changeEvent.getChange(Keys.LOGBACK_COMMON).getNewValue();

        // logback reload
        writeAndReloadLogbackConfig(newConfiguration);
    }

    private void writeAndReloadLogbackConfig(String content) {
        // 将logback-common.xml写入classpath路径下
        FileUtil.writeToClassPath(LOGBACK_COMMON_FILE_NAME, content);

        logger.info("write logback common configuration successfully!");

        logger.info("logback configuration changed, start reload now.");
        LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();

        ContextInitializer ci = new ContextInitializer(loggerContext);
        URL url = ci.findURLOfDefaultConfigurationFile(true);

        try {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(loggerContext);
            loggerContext.reset();
            configurator.doConfigure(url);

            logger.info("finish reload logback configuration");
        } catch (JoranException e) {
            logger.error("reload logback configuration error!", e);
        }

        // 打印加载配置过程遇到的告警或者错误信息
        StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);
    }
}
